#pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<string>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<functional>
#include"log.hpp"
using namespace std;

typedef function<string(const string&)> func_t;

Log lg;

enum{
    SOCKET_ERR=1,
    BIND_ERR=2
};

uint16_t defaultport=8080;
string defaultip="0.0.0.0";
const int size=1024;

class UdpServer
{
public:
    UdpServer(uint16_t port=defaultport,string ip=defaultip)
    :port_(port),ip_(ip),isrunnig_(false)
    {}
    void Init()
    {
        //1.创建udp socket
        sockfd_=socket(AF_INET,SOCK_DGRAM,0);
        if(sockfd_<0)
        {
            lg(Fatal,"socket create error, sockfd: %d",sockfd_);
            exit(SOCKET_ERR);
        }
        lg(Info,"socket create success, sockfd: %d",sockfd_);

        //2. 绑定套接字
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(port_);      //需要保证端口号是网络字节序列，因为端口号是要发送给对方的
        local.sin_addr.s_addr=htonl(INADDR_ANY);
        int n=bind(sockfd_,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            lg(Fatal,"bind error,errno: %d,err string: %s",errno,strerror(errno));
            exit(BIND_ERR);
        }
        lg(Fatal,"bind success,errno: %d,err string: %s",errno,strerror(errno));
    }
    void Run(func_t func)
    {
        isrunnig_=true;
        char inbuffer[size];
        while(isrunnig_)
        {
            struct sockaddr_in client;
            socklen_t len=sizeof(client);
            ssize_t n=recvfrom(sockfd_,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)&client,&len);
            if(n<0)
            {
                lg(Warning,"recvfrom error,errno: %d,err string: %s",errno,strerror(errno));
                continue;
            }
            inbuffer[n]=0;

            //充当一次数据处理
            string info=inbuffer;
            string echo_string=func(info);

            sendto(sockfd_,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)&client,len);
        }
    }
    ~UdpServer()
    {
        if(sockfd_>0)
        {
            close(sockfd_);
        }
    }
private:
    int sockfd_;   //网络文件描述符
    uint16_t port_;   //服务器端口号
    string ip_;
    bool isrunnig_;
};